    .macro	mov_q, reg, val
    .if (((\val) >> 31) == 0 || ((\val) >> 31) == 0x1ffffffff)
    movz	\reg, :abs_g1_s:\val
    .else
    .if (((\val) >> 47) == 0 || ((\val) >> 47) == 0x1ffff)
    movz	\reg, :abs_g2_s:\val
    .else
    movz	\reg, :abs_g3:\val
    movk	\reg, :abs_g2_nc:\val
    .endif
    movk	\reg, :abs_g1_nc:\val
    .endif
    movk	\reg, :abs_g0_nc:\val
    .endm

    .macro	adr_l, dst, sym
    adrp	\dst, \sym
    add	\dst, \dst, :lo12:\sym
    .endm

    .macro	ldr_l, dst, sym, tmp=
    .ifb	\tmp
    adrp	\dst, \sym
    ldr	\dst, [\dst, :lo12:\sym]
    .else
    adrp	\tmp, \sym
    ldr	\dst, [\tmp, :lo12:\sym]
    .endif
    .endm

    .macro	str_l, src, sym, tmp
    adrp	\tmp, \sym
    str	\src, [\tmp, :lo12:\sym]
    .endm

    .macro ldr_this_cpu dst, sym, tmp
    adr_l	\dst, \sym
    mrs	\tmp, tpidr_el1
    ldr	\dst, [\dst, \tmp]
    .endm

    .macro	get_thread_info, rd
    mrs	\rd, sp_el0
    .endm

    .macro	read_ctr, reg
    mrs	\reg, ctr_el0			// read CTR
    nop
    .endm

    .macro	dcache_line_size, reg, tmp
    read_ctr	\tmp
    ubfm		\tmp, \tmp, #16, #19	// cache line size encoding
    mov		\reg, #4		// bytes per word
    lsl		\reg, \reg, \tmp	// actual cache line size
    .endm

    .macro	enable_dbg
    msr	daifclr, #8
    .endm

    .macro	reset_pmuserenr_el0, tmpreg
    mrs	\tmpreg, id_aa64dfr0_el1	// Check ID_AA64DFR0_EL1 PMUVer
    sbfx	\tmpreg, \tmpreg, #8, #4
    cmp	\tmpreg, #1			// Skip if no PMU present
    b.lt	9000f
    msr	pmuserenr_el0, xzr		// Disable PMU access from EL0
9000:
    .endm

    .macro	tcr_set_t0sz, valreg, t0sz
    bfi	\valreg, \t0sz, #TCR_T0SZ_OFFSET, #TCR_TxSZ_WIDTH
    .endm

    .macro	tcr_compute_pa_size, tcr, pos, tmp0, tmp1
    mrs	\tmp0, ID_AA64MMFR0_EL1
    // Narrow PARange to fit the PS field in TCR_ELx
    ubfx	\tmp0, \tmp0, #ID_AA64MMFR0_PARANGE_SHIFT, #3
    mov	\tmp1, #ID_AA64MMFR0_PARANGE_MAX
    cmp	\tmp0, \tmp1
    csel	\tmp0, \tmp1, \tmp0, hi
    bfi	\tcr, \tmp0, \pos, #3
    .endm

    .macro	phys_to_ttbr, ttbr, phys
    mov	\ttbr, \phys
    .endm

// map 页表
// 只映射到 pud, 每一个条目 1G 大小
    .macro	phys_to_pte, pte, phys
    mov	\pte, \phys
    .endm

    .macro compute_indices, vstart, vend, shift, ptrs, istart, iend, count
    lsr	\iend, \vend, \shift
    mov	\istart, \ptrs
    sub	\istart, \istart, #1
    and	\iend, \iend, \istart	// iend = (vend >> shift) & (ptrs - 1)
    mov	\istart, \ptrs
    mul	\istart, \istart, \count
    add	\iend, \iend, \istart	// iend += (count - 1) * ptrs
                    // our entries span multiple tables

    lsr	\istart, \vstart, \shift
    mov	\count, \ptrs
    sub	\count, \count, #1
    and	\istart, \istart, \count

    sub	\count, \iend, \istart
    .endm

    .macro populate_entries, tbl, rtbl, index, eindex, flags, inc, tmp1, sz
.Lpe\@:	phys_to_pte \tmp1, \rtbl
    orr	\tmp1, \tmp1, \flags	// tmp1 = table entry
    str	\tmp1, [\tbl, \index, lsl #3]
    mov \sz, \inc
    add	\rtbl, \rtbl, \sz	// rtbl = pa next level
    add	\index, \index, #1
    cmp	\index, \eindex
    b.ls	.Lpe\@
    .endm

    .macro map_memory, tbl, rtbl, vstart, vend, flags, phys, sz, istart, iend, tmp, count, sv
    add \rtbl, \tbl, #PAGE_SIZE
    mov \sv, \rtbl
    mov \count, #0
    compute_indices \vstart, \vend, #PGD_SHIFT, #PTRS_PER_PGD, \istart, \iend, \count
    populate_entries \tbl, \rtbl, \istart, \iend, #PGD_TYPE_TABLE, #PAGE_SIZE, \tmp, \sz
    mov \tbl, \sv

    compute_indices \vstart, \vend, #PUD_SHIFT, #PTRS_PER_PUD, \istart, \iend, \count
    bic \count, \phys, #PUD_SIZE - 1
    populate_entries \tbl, \count, \istart, \iend, \flags, #PUD_SIZE, \tmp, \sz
    .endm

    .macro	sb
    dsb	nsh
    isb
    .endm

    .macro	clear_address_tag, dst, addr
    tst	\addr, #(1 << 55)
    bic	\dst, \addr, #(0xff << 56)
    csel	\dst, \dst, \addr, eq
    .endm

    .macro disable_daif
    msr	daifset, #0xf
    .endm

    .macro enable_daif
    msr	daifclr, #0xf
    .endm

    .macro	inherit_daif, pstate:req, tmp:req
    and	\tmp, \pstate, #(PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)
    msr	daif, \tmp
    .endm

    .macro enable_da_f
    msr	daifclr, #(8 | 4 | 1)
    .endm
